Synopsis: Fixes buffer overruns in BIND.
NetBSD versions: 1.0, 1.1, 1.2, and 1.2.1, 1.3, 1.3.1.
Thanks to: Internet Software Consortium, CERT.
Reported in CERT Advisory: CA-98.05

Index: CHANGES
===================================================================
RCS file: /cvsroot/src/usr.sbin/named/CHANGES,v
retrieving revision 1.1.1.2
retrieving revision 1.2
diff -c -r1.1.1.2 -r1.2
*** CHANGES	1997/10/04 14:08:21	1.1.1.2
--- CHANGES	1998/05/06 05:21:45	1.2
***************
*** 1,4 ****
! $Id: CHANGES,v 8.53 1997/06/01 20:34:25 vixie Exp vixie 
  
  	--- 4.9.6 released ---
  
--- 1,16 ----
! $Id: CHANGES,v 8.56 1998/04/07 04:59:42 vixie Exp 
! 
! 	--- 4.9.7-T1A released ---
! 
! 808. [security]	A number of routines did insufficient bounds checking which
! 		could cause crashes by reading from an invalid memory
! 		location. (From BIND-8).
! 
! 807. [bug]	The server sometimes leaked the flushset (ns_resp.c).
! 		(From BIND-8).
! 
! 806. [bug]	add_related_additional() leaked memory if the name
! 		was already in the related array.  (From BIND-8).
  
  	--- 4.9.6 released ---
  
Index: Makefile
===================================================================
RCS file: /cvsroot/src/usr.sbin/named/Makefile,v
retrieving revision 1.7
retrieving revision 1.8
diff -c -r1.7 -r1.8
*** Makefile	1996/02/02 15:25:33	1.7
--- Makefile	1998/05/06 05:21:46	1.8
***************
*** 1,8 ****
! #	$NetBSD: Makefile,v 1.7 1996/02/02 15:25:33 mrg Exp $
! # from $Id: Makefile,v 8.1 1994/12/15 06:23:43 vixie Exp 
  
  SUBDIR= named named-xfer ndc reload restart dig nslookup host dnsquery
  
! VER= 4.9.3-P1
  
  .include <bsd.subdir.mk>
--- 1,7 ----
! #	$NetBSD: Makefile,v 1.8 1998/05/06 05:21:46 mrg Exp $
  
  SUBDIR= named named-xfer ndc reload restart dig nslookup host dnsquery
  
! VER= 4.9.7-T1B
  
  .include <bsd.subdir.mk>
Index: README
===================================================================
RCS file: /cvsroot/src/usr.sbin/named/README,v
retrieving revision 1.1.1.2
retrieving revision 1.2
diff -c -r1.1.1.2 -r1.2
*** README	1997/10/04 14:08:26	1.1.1.2
--- README	1998/05/06 05:21:46	1.2
***************
*** 1,18 ****
! The official version of BIND is now 8.1.1.  This is 4.9.6, the last of 4.*
! which we are releasing since it has some important security bugs fixed.
  
  The official place to get BIND is <URL:ftp://ftp.isc.org/isc/bind/src>.
  
! The official mailing lists are:		bind-users@vix.com	- users/admins
!   (use *-request@* for admin mail)	bind-workers@vix.com	- developers
  
! The official Usenet newsgroups are:	comp.protocols.tcp-ip.domains
! 					comp.protocols.dns.bind
! 					comp.protocols.dns.ops
! 					comp.protocols.dns.std
  					
! BIND is currently maintained by:	The Internet Software Consortium
! 					(see <URL:http://www.isc.org/isc>.)
  
  Read the top of CHANGES for interesting stuff.
  
--- 1,24 ----
! Internet Software Consortium
! BIND Release 4.9.7 README
! $Date: 1998/05/06 05:21:46 $
! 
! The official version of ISC BIND is now 8.1.1.  This is ISC BIND 4.9.7,
! hoped to be the last of 4.*, which we are releasing since it has an important
! security bug (plus some memory leaks) fixed.
  
  The official place to get BIND is <URL:ftp://ftp.isc.org/isc/bind/src>.
  
! The official mailing lists are:		<bind-users@vix.com>	- users/admins
!   (use *-request@* for admin mail)	<bind-workers@vix.com>	- developers
  
! The official Usenet newsgroups are:	<URL:news:comp.protocols.dns.bind>
! 					<URL:news:comp.protocols.dns.ops>
! 					<URL:news:comp.protocols.dns.std>
  					
! BIND is maintained by:			The Internet Software Consortium
! 					(see <URL:http://www.isc.org/>)
! 
! Bug reports should be sent to:		<bind-bugs@vix.com>
  
  Read the top of CHANGES for interesting stuff.
  
Index: named/Version.c
===================================================================
RCS file: /cvsroot/src/usr.sbin/named/named/Version.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -c -r1.3 -r1.4
*** Version.c	1997/10/04 15:11:39	1.3
--- Version.c	1998/05/06 05:21:47	1.4
***************
*** 10,16 ****
  char rcsid[] = "from: Id: Version.c,v 8.2 1997/06/01 20:34:34 vixie Exp ";
  #endif /* not lint */
  
! char Version[] = "named %VERSION% %WHEN%\n\t%WHOANDWHERE%";
  char ShortVersion[] = "%VERSION%";
  
  #ifdef COMMENT
--- 10,16 ----
  char rcsid[] = "from: Id: Version.c,v 8.2 1997/06/01 20:34:34 vixie Exp ";
  #endif /* not lint */
  
! char Version[] = "named %VERSION%";
  char ShortVersion[] = "%VERSION%";
  
  #ifdef COMMENT
Index: named/ns_ncache.c
===================================================================
RCS file: /cvsroot/src/usr.sbin/named/named/ns_ncache.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -c -r1.4 -r1.5
*** ns_ncache.c	1998/01/09 08:09:58	1.4
--- ns_ncache.c	1998/05/06 05:21:47	1.5
***************
*** 23,28 ****
--- 23,35 ----
  
  #ifdef NCACHE
  
+ #define BOUNDS_CHECK(ptr, count) \
+ 	do { \
+ 		if ((ptr) + (count) > eom) { \
+ 			return; \
+ 		} \
+ 	} while (0)
+ 
  void
  cache_n_resp(msg, msglen)
  	u_char *msg;
***************
*** 30,36 ****
  {
  	register struct databuf *dp;
  	HEADER *hp;
! 	u_char *cp;
  	char dname[MAXDNAME];
  	int n;
  	int type, class;
--- 37,43 ----
  {
  	register struct databuf *dp;
  	HEADER *hp;
! 	u_char *cp, *eom, *rdatap;
  	char dname[MAXDNAME];
  	int n;
  	int type, class;
***************
*** 38,56 ****
  	int Vcode;
  #endif
  	int flags;
  
  	nameserIncr(from_addr.sin_addr, nssRcvdNXD);
  
  	hp = (HEADER *)msg;
  	cp = msg+HFIXEDSZ;
    
! 	n = dn_expand(msg, msg + msglen, cp, dname, sizeof dname);
  	if (n < 0) {
  		dprintf(1, (ddt, "Query expand name failed:cache_n_resp\n"));
  		hp->rcode = FORMERR;
  		return;
  	}
  	cp += n;
  	GETSHORT(type, cp);
  	GETSHORT(class, cp);
  	dprintf(1, (ddt,
--- 45,66 ----
  	int Vcode;
  #endif
  	int flags;
+ 	u_int dlen;
  
  	nameserIncr(from_addr.sin_addr, nssRcvdNXD);
  
  	hp = (HEADER *)msg;
  	cp = msg+HFIXEDSZ;
+ 	eom = msg + msglen;
    
! 	n = dn_expand(msg, eom, cp, dname, sizeof dname);
  	if (n < 0) {
  		dprintf(1, (ddt, "Query expand name failed:cache_n_resp\n"));
  		hp->rcode = FORMERR;
  		return;
  	}
  	cp += n;
+ 	BOUNDS_CHECK(cp, 2 * INT16SZ);
  	GETSHORT(type, cp);
  	GETSHORT(class, cp);
  	dprintf(1, (ddt,
***************
*** 78,90 ****
  		if (hp->rcode == NXDOMAIN)
  			type = T_SOA;
  
! 		/* store ther SOA record */
! 		n = dn_skipname(tp, msg + msglen);
  		if (n < 0) {
  			dprintf(3, (ddt, "ncache: form error\n"));
  			return;
  		}
  		tp += n;
  		GETSHORT(atype, tp);		/* type */
  		if (atype != T_SOA) {
  			dprintf(3, (ddt,
--- 88,101 ----
  		if (hp->rcode == NXDOMAIN)
  			type = T_SOA;
  
! 		/* store their SOA record */
! 		n = dn_skipname(tp, eom);
  		if (n < 0) {
  			dprintf(3, (ddt, "ncache: form error\n"));
  			return;
  		}
  		tp += n;
+ 		BOUNDS_CHECK(tp, 3 * INT16SZ + INT32SZ);
  		GETSHORT(atype, tp);		/* type */
  		if (atype != T_SOA) {
  			dprintf(3, (ddt,
***************
*** 93,102 ****
  		}
  		tp += INT16SZ;		/* class */
  		GETLONG(ttl, tp);	/* ttl */
! 		tp += INT16SZ;		/* dlen */
  
  		/* origin */
! 		n = dn_expand(msg, msg + msglen, tp, (char*)data, len);
  		if (n < 0) {
  			dprintf(3, (ddt, "ncache: form error 2\n"));
  			return;
--- 104,115 ----
  		}
  		tp += INT16SZ;		/* class */
  		GETLONG(ttl, tp);	/* ttl */
! 		GETSHORT(dlen, tp);	/* dlen */
! 		BOUNDS_CHECK(tp, dlen);
! 		rdatap = tp;
  
  		/* origin */
! 		n = dn_expand(msg, eom, tp, (char*)data, len);
  		if (n < 0) {
  			dprintf(3, (ddt, "ncache: form error 2\n"));
  			return;
***************
*** 115,124 ****
  		n = strlen((char*)cp1) + 1;
  		cp1 += n;
  		len -= n;
! 		bcopy(tp, cp1, n = 5 * INT32SZ);
  		/* serial, refresh, retry, expire, min */
  		cp1 += n;
  		len -= n;
  		/* store the zone of the soa record */
  		n = dn_expand(msg, msg + msglen, cp, (char*)cp1, len);
  		if (n < 0) {
--- 128,144 ----
  		n = strlen((char*)cp1) + 1;
  		cp1 += n;
  		len -= n;
! 		n = 5 * INT32SZ;
! 		BOUNDS_CHECK(tp, n);
! 		bcopy(tp, cp1, n);
  		/* serial, refresh, retry, expire, min */
  		cp1 += n;
  		len -= n;
+ 		tp += n;
+ 		if (tp != rdatap + dlen) {
+ 			dprintf(3, (ddt, "ncache: form error 2\n"));
+ 			return;
+ 		}
  		/* store the zone of the soa record */
  		n = dn_expand(msg, msg + msglen, cp, (char*)cp1, len);
  		if (n < 0) {
Index: named/ns_req.c
===================================================================
RCS file: /cvsroot/src/usr.sbin/named/named/ns_req.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -c -r1.6 -r1.7
*** ns_req.c	1998/04/07 14:05:07	1.6
--- ns_req.c	1998/05/06 05:21:47	1.7
***************
*** 331,336 ****
--- 331,341 ----
  		hp->rcode = FORMERR;
  		return (Finish);
  	}
+ 	if (*cpp + 2 * INT16SZ > eom) {
+ 		dprintf(1, (ddt, "FORMERR notify too short"));
+ 		hp->rcode = FORMERR;
+ 		return (Finish);
+ 	}
  	*cpp += n;
  	GETSHORT(type, *cpp);
  	GETSHORT(class, *cpp);
***************
*** 464,476 ****
  		return (Finish);
  	}
  	*cpp += n;
! 	GETSHORT(type, *cpp);
! 	GETSHORT(class, *cpp);
! 	if (*cpp > eom) {
  		dprintf(1, (ddt, "FORMERR Query message length short\n"));
  		hp->rcode = FORMERR;
  		return (Finish);
  	}
  	if (*cpp < eom) {
  		dprintf(6, (ddt,"message length > received message\n"));
  		*msglenp = *cpp - msg;
--- 469,481 ----
  		return (Finish);
  	}
  	*cpp += n;
! 	if (*cpp + 2 * INT16SZ > eom) {
  		dprintf(1, (ddt, "FORMERR Query message length short\n"));
  		hp->rcode = FORMERR;
  		return (Finish);
  	}
+ 	GETSHORT(type, *cpp);
+ 	GETSHORT(class, *cpp);
  	if (*cpp < eom) {
  		dprintf(6, (ddt,"message length > received message\n"));
  		*msglenp = *cpp - msg;
***************
*** 993,998 ****
--- 998,1008 ----
  		return (Finish);
  	}
  	*cpp += n;
+ 	if (*cpp + 3 * INT16SZ + INT32SZ > eom) {
+ 		dprintf(1, (ddt, "FORMERR IQuery message too short"));
+ 		hp->rcode = FORMERR;
+ 		return (Finish);
+ 	}
  	GETSHORT(type, *cpp);
  	GETSHORT(class, *cpp);
  	*cpp += INT32SZ;	/* ttl */
***************
*** 1074,1079 ****
--- 1084,1093 ----
  					return (Finish);
  				}
  				*cpp += n;
+ 				if (*cpp + 2 * INT16SZ > dnbuf + *buflenp) {
+ 					hp->tc = 1;
+ 					return (Finish);
+ 				}
  				PUTSHORT((u_int16_t)dp->d_type, *cpp);
  				PUTSHORT((u_int16_t)dp->d_class, *cpp);
  				*buflenp -= n;
***************
*** 1262,1267 ****
--- 1276,1283 ----
  	}
  
  	buflen -= RRFIXEDSZ;
+ 	if (buflen < 0)
+ 		return (-1);
  #if defined(RETURNSOA) && defined(NCACHE)
  	if (dp->d_rcode) {
  		name = (char *)dp->d_data;
***************
*** 1275,1280 ****
--- 1291,1298 ----
  		return (-1);
  	cp = buf + n;
  	buflen -= n;
+ 	if (buflen < 0)
+ 		return (-1);
  	PUTSHORT((u_int16_t)type, cp);
  	PUTSHORT((u_int16_t)dp->d_class, cp);
  	PUTLONG(ttl, cp);
***************
*** 1314,1319 ****
--- 1332,1339 ----
  			return (-1);
  		cp += n;
  		buflen -= type == T_SOA ? n + 5 * INT32SZ : n;
+ 		if (buflen < 0)
+ 			return (-1);
  		cp1 += strlen((char *)cp1) + 1;
  		n = dn_comp((char *)cp1, cp, buflen, dnptrs, edp);
  		if (n < 0)
***************
*** 1332,1341 ****
  		/* cp1 == our data/ cp == data of RR */
  		cp1 = dp->d_data;
  
-  		if ((buflen -= INT16SZ) < 0)
- 			return (-1);
- 
   		/* copy order */
   		bcopy(cp1, cp, INT16SZ);
   		cp += INT16SZ;
   		cp1 += INT16SZ;
--- 1352,1361 ----
  		/* cp1 == our data/ cp == data of RR */
  		cp1 = dp->d_data;
  
   		/* copy order */
+ 		buflen -= INT16SZ;
+ 		if (buflen < 0)
+ 			return (-1);
   		bcopy(cp1, cp, INT16SZ);
   		cp += INT16SZ;
   		cp1 += INT16SZ;
***************
*** 1343,1348 ****
--- 1363,1371 ----
  		dprintf(1, (ddt, "current size n = %u\n", n));
  
  		/* copy preference */
+ 		buflen -= INT16SZ;
+ 		if (buflen < 0)
+ 			return (-1);
  		bcopy(cp1, cp, INT16SZ);
  		cp += INT16SZ;
  		cp1 += INT16SZ;
***************
*** 1351,1356 ****
--- 1374,1382 ----
  
  		/* Flags */
  		n = *cp1++;
+ 		buflen -= n + 1;
+ 		if (buflen < 0)
+ 			return (-1);
  		dprintf(1, (ddt, "size of n at flags = %d\n", n));
  		*cp++ = n;
  		bcopy(cp1,cp,n);
***************
*** 1361,1366 ****
--- 1387,1395 ----
  		
  		/* Service */
  		n = *cp1++;
+ 		buflen -= n + 1;
+ 		if (buflen < 0)
+ 			return (-1);
  		*cp++ = n;
  		bcopy(cp1,cp,n);
  		cp += n;
***************
*** 1370,1375 ****
--- 1399,1407 ----
  
  		/* Regexp */
  		n = *cp1++;
+ 		buflen -= n + 1;
+ 		if (buflen < 0)
+ 			return (-1);
  		*cp++ = n;
  		bcopy(cp1,cp,n);
  		cp += n;
***************
*** 1408,1413 ****
--- 1440,1448 ----
   		cp1 += INT16SZ;
  
  		if (type == T_SRV) {
+ 			buflen -= INT16SZ*2;
+ 			if (buflen < 0)
+ 				return (-1);
  			bcopy(cp1, cp, INT16SZ*2);
  			cp += INT16SZ*2;
  			cp1 += INT16SZ*2;
Index: named/ns_resp.c
===================================================================
RCS file: /cvsroot/src/usr.sbin/named/named/ns_resp.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -c -r1.4 -r1.5
*** ns_resp.c	1997/10/04 15:12:09	1.4
--- ns_resp.c	1998/05/06 05:21:48	1.5
***************
*** 134,140 ****
  static void		rrsetadd __P((struct flush_set *, char *,
  				      struct databuf *)),
  			rrsetupdate __P((struct flush_set *, int flags)),
! 			flushrrset __P((struct flush_set *));
  static int		rrsetcmp __P((char *, struct db_list *)),
  			check_root __P((void)),
  			check_ns __P((void)),
--- 134,141 ----
  static void		rrsetadd __P((struct flush_set *, char *,
  				      struct databuf *)),
  			rrsetupdate __P((struct flush_set *, int flags)),
! 			flushrrset __P((struct flush_set *)),
! 			free_flushset __P((struct flush_set *));
  static int		rrsetcmp __P((char *, struct db_list *)),
  			check_root __P((void)),
  			check_ns __P((void)),
***************
*** 241,247 ****
  	register struct databuf *ns, *ns2;
  	register u_char *cp;
  	u_char *eom = msg + msglen;
! 	struct flush_set *flushset;
  	struct sockaddr_in *nsa;
  	struct databuf *nsp[NSMAX];
  	int i, c, n, qdcount, ancount, aucount, nscount, arcount, arfirst;
--- 242,248 ----
  	register struct databuf *ns, *ns2;
  	register u_char *cp;
  	u_char *eom = msg + msglen;
! 	struct flush_set *flushset = NULL;
  	struct sockaddr_in *nsa;
  	struct databuf *nsp[NSMAX];
  	int i, c, n, qdcount, ancount, aucount, nscount, arcount, arfirst;
***************
*** 266,273 ****
  	struct fwdinfo *fwd;
  	char *tname = NULL;
  
- 	free_related_additional();
- 
  	nameserIncr(from_addr.sin_addr, nssRcvdR);
  	nsp[0] = NULL;
  	hp = (HEADER *) msg;
--- 267,272 ----
***************
*** 304,309 ****
--- 303,312 ----
  			goto formerr;
  		}
  		cp += n;
+ 		if (cp + 2 * INT16SZ > eom) {
+ 			formerrmsg = outofDataQuery;
+ 			goto formerr;
+ 		}
  		GETSHORT(qtype, cp);
  		GETSHORT(qclass, cp);
  		if (!ns_nameok(qname, qclass, response_trans,
***************
*** 584,599 ****
  			goto formerr;
  		}
  		tp += n;
! 		GETSHORT(type, tp);
! 		if (tp >= eom) {
  			formerrmsg = outofDataAuth;
  			goto formerr;
  		}
  		GETSHORT(class, tp);
- 		if (tp >= eom) {
- 			formerrmsg = outofDataAuth;
- 			goto formerr;
- 		}
  		if (!ns_nameok(name, class, response_trans,
  			       ns_ownercontext(type, response_trans),
  			       name, from_addr.sin_addr)) {
--- 587,598 ----
  			goto formerr;
  		}
  		tp += n;
! 		if (tp + 2 * INT16SZ > eom) {
  			formerrmsg = outofDataAuth;
  			goto formerr;
  		}
+ 		GETSHORT(type, tp);
  		GETSHORT(class, tp);
  		if (!ns_nameok(name, class, response_trans,
  			       ns_ownercontext(type, response_trans),
  			       name, from_addr.sin_addr)) {
***************
*** 649,654 ****
--- 648,654 ----
  			u_int16_t type, class, dlen;
  			u_int32_t serial;
  			u_char *tp = cp;
+ 			u_char *rdatap;
  
  			n = dn_expand(msg, eom, tp, name, sizeof name);
  			if (n < 0) {
***************
*** 656,669 ****
  				goto formerr;
  			}
  			tp += n;  		/* name */
  			GETSHORT(type, tp);	/* type */
  			GETSHORT(class, tp);	/* class */
  			tp += INT32SZ;		/* ttl */
  			GETSHORT(dlen, tp); 	/* dlen */
! 			if (tp >= eom) {
! 				formerrmsg = outofDataAnswer;
! 				goto formerr;
! 			}
  			if (!ns_nameok(name, class, response_trans,
  				       ns_ownercontext(type, response_trans),
  				       name, from_addr.sin_addr)) {
--- 656,670 ----
  				goto formerr;
  			}
  			tp += n;  		/* name */
+ 			if (tp + 3 * INT16SZ + INT32SZ > eom) {
+ 				formerrmsg = outofDataAnswer;
+ 				goto formerr;
+ 			}
  			GETSHORT(type, tp);	/* type */
  			GETSHORT(class, tp);	/* class */
  			tp += INT32SZ;		/* ttl */
  			GETSHORT(dlen, tp); 	/* dlen */
! 			rdatap = tp;		/* start of rdata */
  			if (!ns_nameok(name, class, response_trans,
  				       ns_ownercontext(type, response_trans),
  				       name, from_addr.sin_addr)) {
***************
*** 679,688 ****
  				formerrmsg = msgbuf;
  				goto formerr;
  			}
- 			if ((u_int)dlen < (5 * INT32SZ)) {
- 				formerrmsg = dlenUnderrunAnswer;
- 				goto formerr;
- 			}
  
  			if (0 >= (n = dn_skipname(tp, eom))) {
  				formerrmsg = skipnameFailedAnswer;
--- 680,685 ----
***************
*** 694,700 ****
--- 691,706 ----
  				goto formerr;
  			}
  			tp += n;  		/* rname */
+ 			if (tp + 5 * INT32SZ > eom) {
+ 				formerrmsg = dlenUnderrunAnswer;
+ 				goto formerr;
+ 			}
  			GETLONG(serial, tp);
+ 			tp += 4 * INT32SZ;	/* Skip rest of SOA. */
+ 			if ((u_int)(tp - rdatap) != dlen) {
+ 				formerrmsg = dlenOverrunAnswer;
+ 				goto formerr;
+ 			}
  
  			qserial_answer(qp, serial);
  			qremove(qp);
***************
*** 790,801 ****
--- 796,813 ----
  
  		maybe_free(&tname);
  		if (cp >= eom) {
+ 			free_related_additional();
+ 			if (flushset != NULL)
+ 				free_flushset(flushset);
  			formerrmsg = outofDataFinal;
  			goto formerr;
  		}
  		n = rrextract(msg, msglen, cp, &dp, name, sizeof name, &tname);
  		if (n < 0) {
+ 			free_related_additional();
  			maybe_free(&tname);
+ 			if (flushset != NULL)
+ 				free_flushset(flushset);
  			formerrmsg = outofDataFinal;
  			goto formerr;
  		}
***************
*** 925,937 ****
  		}
  		rrsetadd(flushset, name, dp);
  	}
  	maybe_free(&tname);
  	if (flushset) {
  		rrsetupdate(flushset, dbflags);
! 		for (i = 0; i < count; i++)
! 			if (flushset[i].fs_name)
! 				free(flushset[i].fs_name);
! 		free((char*)flushset);
  	}
  	if (lastwascname && !externalcname)
  		syslog(LOG_DEBUG, "%s (%s)", danglingCname, aname);
--- 937,947 ----
  		}
  		rrsetadd(flushset, name, dp);
  	}
+ 	free_related_additional();
  	maybe_free(&tname);
  	if (flushset) {
  		rrsetupdate(flushset, dbflags);
! 		free_flushset(flushset);
  	}
  	if (lastwascname && !externalcname)
  		syslog(LOG_DEBUG, "%s (%s)", danglingCname, aname);
***************
*** 1370,1375 ****
--- 1380,1393 ----
  	return;
  }
  
+ #define BOUNDS_CHECK(ptr, count) \
+ 	do { \
+ 		if ((ptr) + (count) > eom) { \
+ 			hp->rcode = FORMERR; \
+ 			return (-1); \
+ 		} \
+ 	} while (0)
+ 
  static int
  rrextract(msg, msglen, rrp, dpp, dname, namelen, tnamep)
  	u_char *msg;
***************
*** 1380,1386 ****
  	int namelen;
  	char **tnamep;
  {
! 	register u_char *cp;
  	register int n;
  	int class, type, dlen, n1;
  	u_int32_t ttl;
--- 1398,1404 ----
  	int namelen;
  	char **tnamep;
  {
! 	register u_char *cp, *eom, *rdatap;
  	register int n;
  	int class, type, dlen, n1;
  	u_int32_t ttl;
***************
*** 1394,1408 ****
  
  	*dpp = NULL;
  	cp = rrp;
! 	if ((n = dn_expand(msg, msg + msglen, cp, dname, namelen)) < 0) {
  		hp->rcode = FORMERR;
  		return (-1);
  	}
  	cp += n;
  	GETSHORT(type, cp);
  	GETSHORT(class, cp);
  	GETLONG(ttl, cp);
  	GETSHORT(dlen, cp);
  	if (!ns_nameok(dname, class, response_trans,
  		       ns_ownercontext(type, response_trans),
  		       dname, from_addr.sin_addr)) {
--- 1412,1430 ----
  
  	*dpp = NULL;
  	cp = rrp;
! 	eom = msg + msglen;
! 	if ((n = dn_expand(msg, eom, cp, dname, namelen)) < 0) {
  		hp->rcode = FORMERR;
  		return (-1);
  	}
  	cp += n;
+ 	BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ);
  	GETSHORT(type, cp);
  	GETSHORT(class, cp);
  	GETLONG(ttl, cp);
  	GETSHORT(dlen, cp);
+ 	BOUNDS_CHECK(cp, dlen);
+ 	rdatap = cp;
  	if (!ns_nameok(dname, class, response_trans,
  		       ns_ownercontext(type, response_trans),
  		       dname, from_addr.sin_addr)) {
***************
*** 1461,1468 ****
  	case T_MR:
  	case T_NS:
  	case T_PTR:
! 		n = dn_expand(msg, msg + msglen, cp,
! 			      (char *)data, sizeof data);
  		if (n < 0) {
  			hp->rcode = FORMERR;
  			return (-1);
--- 1483,1489 ----
  	case T_MR:
  	case T_NS:
  	case T_PTR:
! 		n = dn_expand(msg, eom, cp, (char *)data, sizeof data);
  		if (n < 0) {
  			hp->rcode = FORMERR;
  			return (-1);
***************
*** 1488,1495 ****
  		context = mailname_ctx;
  		/* FALLTHROUGH */
  	soa_rp_minfo:
! 		n = dn_expand(msg, msg + msglen, cp,
! 			      (char *)data, sizeof data);
  		if (n < 0) {
  			hp->rcode = FORMERR;
  			return (-1);
--- 1509,1515 ----
  		context = mailname_ctx;
  		/* FALLTHROUGH */
  	soa_rp_minfo:
! 		n = dn_expand(msg, eom, cp, (char *)data, sizeof data);
  		if (n < 0) {
  			hp->rcode = FORMERR;
  			return (-1);
***************
*** 1500,1510 ****
  			return (-1);
  		}
  		cp += n;
  		cp1 = data + (n = strlen((char *)data) + 1);
  		n1 = sizeof(data) - n;
  		if (type == T_SOA)
  			n1 -= 5 * INT32SZ;
! 		n = dn_expand(msg, msg + msglen, cp, (char *)cp1, n1);
  		if (n < 0) {
  			hp->rcode = FORMERR;
  			return (-1);
--- 1520,1534 ----
  			return (-1);
  		}
  		cp += n;
+ 		/*
+ 		 * The next use of 'cp' is dn_expand(), so we don't have
+ 		 * to BOUNDS_CHECK() here.
+ 		 */
  		cp1 = data + (n = strlen((char *)data) + 1);
  		n1 = sizeof(data) - n;
  		if (type == T_SOA)
  			n1 -= 5 * INT32SZ;
! 		n = dn_expand(msg, eom, cp, (char *)cp1, n1);
  		if (n < 0) {
  			hp->rcode = FORMERR;
  			return (-1);
***************
*** 1521,1527 ****
  		cp += n;
  		cp1 += strlen((char *)cp1) + 1;
  		if (type == T_SOA) {
! 			bcopy(cp, cp1, n = 5 * INT32SZ);
  			cp += n;
  			cp1 += n;
  		}
--- 1545,1553 ----
  		cp += n;
  		cp1 += strlen((char *)cp1) + 1;
  		if (type == T_SOA) {
! 			n = 5 * INT32SZ;
! 			BOUNDS_CHECK(cp, n);
! 			bcopy(cp, cp1, n);
  			cp += n;
  			cp1 += n;
  		}
***************
*** 1531,1560 ****
  
  	case T_NAPTR:
  		/* Grab weight and port. */
  		bcopy(cp, data, INT16SZ*2);
  		cp1 = data + INT16SZ*2;
  		cp += INT16SZ*2;
  
  		/* Flags */
  		n = *cp++;
  		*cp1++ = n;
  		bcopy(cp, cp1, n);
  		cp += n; cp1 += n;
  
  		/* Service */
  		n = *cp++;
  		*cp1++ = n;
  		bcopy(cp, cp1, n);
  		cp += n; cp1 += n;
  
  		/* Regexp */
  		n = *cp++;
  		*cp1++ = n;
  		bcopy(cp, cp1, n);
  		cp += n; cp1 += n;
  
  		/* Replacement */
! 		n = dn_expand(msg, msg + msglen, cp, (char *)cp1,
  			      sizeof data - (cp1 - data));
  		if (n < 0) {
  			hp->rcode = FORMERR;
--- 1557,1593 ----
  
  	case T_NAPTR:
  		/* Grab weight and port. */
+ 		BOUNDS_CHECK(cp, INT16SZ*2);
  		bcopy(cp, data, INT16SZ*2);
  		cp1 = data + INT16SZ*2;
  		cp += INT16SZ*2;
  
  		/* Flags */
+ 		BOUNDS_CHECK(cp, 1);
  		n = *cp++;
+ 		BOUNDS_CHECK(cp, n);
  		*cp1++ = n;
  		bcopy(cp, cp1, n);
  		cp += n; cp1 += n;
  
  		/* Service */
+ 		BOUNDS_CHECK(cp, 1);
  		n = *cp++;
+ 		BOUNDS_CHECK(cp, n);
  		*cp1++ = n;
  		bcopy(cp, cp1, n);
  		cp += n; cp1 += n;
  
  		/* Regexp */
+ 		BOUNDS_CHECK(cp, 1);
  		n = *cp++;
+ 		BOUNDS_CHECK(cp, n);
  		*cp1++ = n;
  		bcopy(cp, cp1, n);
  		cp += n; cp1 += n;
  
  		/* Replacement */
! 		n = dn_expand(msg, eom, cp, (char *)cp1,
  			      sizeof data - (cp1 - data));
  		if (n < 0) {
  			hp->rcode = FORMERR;
***************
*** 1579,1597 ****
  	case T_RT:
  	case T_SRV:
  		/* grab preference */
  		bcopy(cp, data, INT16SZ);
  		cp1 = data + INT16SZ;
  		cp += INT16SZ;
  
  		if (type == T_SRV) {
  			/* Grab weight and port. */
  			bcopy(cp, cp1, INT16SZ*2);
  			cp1 += INT16SZ*2;
  			cp += INT16SZ*2;
  		}
  
  		/* get name */
! 		n = dn_expand(msg, msg + msglen, cp, (char *)cp1,
  			      sizeof data - (cp1 - data));
  		if (n < 0) {
  			hp->rcode = FORMERR;
--- 1612,1632 ----
  	case T_RT:
  	case T_SRV:
  		/* grab preference */
+ 		BOUNDS_CHECK(cp, INT16SZ);
  		bcopy(cp, data, INT16SZ);
  		cp1 = data + INT16SZ;
  		cp += INT16SZ;
  
  		if (type == T_SRV) {
  			/* Grab weight and port. */
+ 			BOUNDS_CHECK(cp, INT16SZ*2);
  			bcopy(cp, cp1, INT16SZ*2);
  			cp1 += INT16SZ*2;
  			cp += INT16SZ*2;
  		}
  
  		/* get name */
! 		n = dn_expand(msg, eom, cp, (char *)cp1,
  			      sizeof data - (cp1 - data));
  		if (n < 0) {
  			hp->rcode = FORMERR;
***************
*** 1616,1628 ****
  
  	case T_PX:
  		/* grab preference */
  		bcopy(cp, data, INT16SZ);
  		cp1 = data + INT16SZ;
  		cp += INT16SZ;
  
  		/* get MAP822 name */
! 		n = dn_expand(msg, msg + msglen, cp, (char *)cp1,
! 				sizeof data - INT16SZ);
  		if (n < 0) {
  			hp->rcode = FORMERR;
  			return (-1);
--- 1651,1664 ----
  
  	case T_PX:
  		/* grab preference */
+ 		BOUNDS_CHECK(cp, INT16SZ);
  		bcopy(cp, data, INT16SZ);
  		cp1 = data + INT16SZ;
  		cp += INT16SZ;
  
  		/* get MAP822 name */
! 		n = dn_expand(msg, eom, cp, (char *)cp1,
! 			      sizeof data - INT16SZ);
  		if (n < 0) {
  			hp->rcode = FORMERR;
  			return (-1);
***************
*** 1633,1641 ****
  			return (-1);
  		}
  		cp += n;
  		cp1 += (n = strlen((char *)cp1) + 1);
  		n1 = sizeof(data) - n;
! 		n = dn_expand(msg, msg + msglen, cp, (char *)cp1, n1);
  		if (n < 0) {
  			hp->rcode = FORMERR;
  			return (-1);
--- 1669,1681 ----
  			return (-1);
  		}
  		cp += n;
+ 		/*
+ 		 * The next use of 'cp' is dn_expand(), so we don't have
+ 		 * to BOUNDS_CHECK() here.
+ 		 */
  		cp1 += (n = strlen((char *)cp1) + 1);
  		n1 = sizeof(data) - n;
! 		n = dn_expand(msg, eom, cp, (char *)cp1, n1);
  		if (n < 0) {
  			hp->rcode = FORMERR;
  			return (-1);
***************
*** 1658,1663 ****
--- 1698,1704 ----
  		/* This code is similar to that in db_load.c.  */
  
  		/* Skip coveredType, alg, labels */
+ 		BOUNDS_CHECK(cp, INT16SZ + 1 + 1 + 3*INT32SZ);
  		cp1 = cp + INT16SZ + 1 + 1;
  		GETLONG(origTTL, cp1);
  		GETLONG(exptime, cp1);
***************
*** 1702,1724 ****
  
  		/* first just copy over the type_covered, algorithm, */
  		/* labels, orig ttl, two timestamps, and the footprint */
  		bcopy(cp, cp1, 18);
  		cp  += 18;
  		cp1 += 18;
  
  		/* then the signer's name */
! 		n = dn_expand(msg, msg + msglen, cp,
! 			      (char *)cp1, (sizeof data) - 18);
! 		if (n < 0)
  			return (-1);
  		cp += n;
  		cp1 += strlen((char*)cp1)+1;
  
  		/* finally, we copy over the variable-length signature.
  		   Its size is the total data length, minus what we copied. */
  		n = dlen - (18 + n);
! 		if (n > (sizeof data) - (cp1 - (u_char *)data))
  			return (-1);  /* out of room! */
  		bcopy(cp, cp1, n);
  		cp += n;
  		cp1 += n;
--- 1743,1773 ----
  
  		/* first just copy over the type_covered, algorithm, */
  		/* labels, orig ttl, two timestamps, and the footprint */
+ 		BOUNDS_CHECK(cp, 18);
  		bcopy(cp, cp1, 18);
  		cp  += 18;
  		cp1 += 18;
  
  		/* then the signer's name */
! 		n = dn_expand(msg, eom, cp, (char *)cp1, (sizeof data) - 18);
! 		if (n < 0) {
! 			hp->rcode = FORMERR;
  			return (-1);
+ 		}
  		cp += n;
  		cp1 += strlen((char*)cp1)+1;
  
  		/* finally, we copy over the variable-length signature.
  		   Its size is the total data length, minus what we copied. */
+ 		if (18 + (u_int)n > dlen) {
+ 			hp->rcode = FORMERR;
+ 			return (-1);
+ 		}
  		n = dlen - (18 + n);
! 		if (n > ((int)(sizeof data) - (int)(cp1 - (u_char *)data))) {
! 			hp->rcode = FORMERR;
  			return (-1);  /* out of room! */
+ 		}
  		bcopy(cp, cp1, n);
  		cp += n;
  		cp1 += n;
***************
*** 1733,1738 ****
--- 1782,1799 ----
  		dprintf(3, (ddt, "unknown type %d\n", type));
  		return ((cp - rrp) + dlen);
  	}
+ 
+ 	if (cp > eom) {
+ 		hp->rcode = FORMERR;
+ 		return (-1);
+ 	}
+ 	if ((u_int)(cp - rdatap) != dlen) {
+ 		dprintf(3, (ddt,
+ 		      "encoded rdata length is %u, but actual length was %u",
+ 			    dlen, (u_int)(cp - rdatap)));
+ 		hp->rcode = FORMERR;
+ 		return (-1);
+ 	}
  	if (n > MAXDATA) {
  		dprintf(1, (ddt,
  			    "update type %d: %d bytes is too much data\n",
***************
*** 3071,3076 ****
--- 3132,3148 ----
  	db_free(dp);
  }
  
+ static void
+ free_flushset(flushset)
+ 	struct flush_set *flushset;
+ {
+ 	struct flush_set *fs;
+ 
+ 	for (fs = flushset; fs->fs_name != NULL; fs++)
+ 		free(fs->fs_name);
+ 	free((char *)flushset);
+ }
+ 
  /*
   *  This is best thought of as a "cache invalidate" function.
   *  It is called whenever a piece of data is determined to have
***************
*** 3133,3140 ****
  	if (num_related >= MAX_RELATED - 1)
  		return;
  	for (i = 0; i < num_related; i++)
! 		if (strcasecmp(name, related[i]) == 0)
  			return;
  	related[num_related++] = name;
  }
  
--- 3205,3214 ----
  	if (num_related >= MAX_RELATED - 1)
  		return;
  	for (i = 0; i < num_related; i++)
! 		if (strcasecmp(name, related[i]) == 0) {
! 			free(name);
  			return;
+ 		}
  	related[num_related++] = name;
  }
  
Index: named/version.c
===================================================================
RCS file: /cvsroot/src/usr.sbin/named/named/version.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -c -r1.3 -r1.4
*** version.c	1997/10/04 15:12:21	1.3
--- version.c	1998/05/06 05:21:48	1.4
***************
*** 6,17 ****
   */
  
  #ifndef lint
! char sccsid[] = "@(#)named 4.9.6";
  char rcsid[] = "from: Id: Version.c,v 8.2 1997/06/01 20:34:34 vixie Exp ";
  #endif /* not lint */
  
! char Version[] = "named 4.9.6";
! char ShortVersion[] = "4.9.6";
  
  #ifdef COMMENT
  
--- 6,17 ----
   */
  
  #ifndef lint
! char sccsid[] = "@(#)named 4.9.7-T1B %WHEN% %WHOANDWHERE%";
  char rcsid[] = "from: Id: Version.c,v 8.2 1997/06/01 20:34:34 vixie Exp ";
  #endif /* not lint */
  
! char Version[] = "named 4.9.7-T1B";
! char ShortVersion[] = "4.9.7-T1B";
  
  #ifdef COMMENT
  
Index: named-xfer/named-xfer.c
===================================================================
RCS file: /cvsroot/src/usr.sbin/named/named-xfer/named-xfer.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -c -r1.6 -r1.7
*** named-xfer.c	1998/03/30 02:31:22	1.6
--- named-xfer.c	1998/05/06 05:21:49	1.7
***************
*** 94,100 ****
  
  #if !defined(lint) && !defined(SABER)
  static char sccsid[] = "@(#)named-xfer.c	4.18 (Berkeley) 3/7/91";
! static char rcsid[] = "from: Id: named-xfer.c,v 8.23 1997/06/01 20:34:34 vixie Exp ";
  #endif /* not lint */
  
  #include <sys/types.h>
--- 94,100 ----
  
  #if !defined(lint) && !defined(SABER)
  static char sccsid[] = "@(#)named-xfer.c	4.18 (Berkeley) 3/7/91";
! static char rcsid[] = "from: Id: named-xfer.c,v 8.24 1998/04/07 04:59:45 vixie Exp ";
  #endif /* not lint */
  
  #include <sys/types.h>
***************
*** 742,747 ****
--- 742,751 ----
  			goto badsoa;
  		}
  		tmp += n;
+ 		if (tmp + 2 * INT16SZ > eom) {
+ 			badsoa_msg = "query error";
+ 			goto badsoa;
+ 		}
  		GETSHORT(type, tmp);
  		GETSHORT(class, tmp);
  		if (class != curclass || type != T_SOA ||
***************
*** 780,785 ****
--- 784,793 ----
  			GETSHORT(class, cp4);
  			GETLONG(ttl, cp4);
  			GETSHORT(dlen, cp4);
+ 			if (cp4 + dlen > eom) {
+ 				badsoa_msg = "zinfo dlen too big";
+ 				goto badsoa;
+ 			}
  			if (type == T_SOA)
  				break;
  			/* Skip to next record, if any.  */
***************
*** 1157,1162 ****
--- 1165,1172 ----
  	register int n;
  	int type, class;
  	u_long ttl;
+ 	u_int dlen;
+ 	u_char *rdatap;
  
  	/* Are type, class, and ttl OK? */
  	if (eom - cp < 3 * INT16SZ + INT32SZ)
***************
*** 1164,1170 ****
  	GETSHORT(type, cp);
  	GETSHORT(class, cp);
  	GETLONG(ttl, cp);
! 	cp += INT16SZ;	/* dlen */
  	if (type != T_SOA || class != curclass)
  		return ("zinfo wrong typ/cla/ttl");
  	/* Skip master name and contact name, we can't validate them. */
--- 1174,1181 ----
  	GETSHORT(type, cp);
  	GETSHORT(class, cp);
  	GETLONG(ttl, cp);
! 	GETSHORT(dlen, cp);
! 	rdatap = cp;
  	if (type != T_SOA || class != curclass)
  		return ("zinfo wrong typ/cla/ttl");
  	/* Skip master name and contact name, we can't validate them. */
***************
*** 1182,1190 ****
--- 1193,1211 ----
  	GETLONG(zp->z_retry, cp);
  	GETLONG(zp->z_expire, cp);
  	GETLONG(zp->z_minimum, cp);
+ 	if (cp != rdatap + dlen)
+ 		return ("bad soa dlen");
  	return (NULL);
  }
  
+ #define BOUNDS_CHECK(ptr, count) \
+ 	do { \
+ 		if ((ptr) + (count) > eom) { \
+ 			hp->rcode = FORMERR; \
+ 			return (-1); \
+ 		} \
+ 	} while (0)
+ 
  /*
   * Parse the message, determine if it should be printed, and if so, print it
   * in .db file form.
***************
*** 1204,1210 ****
  	int i, j, tab, result, class, type, dlen, n1, n;
  	char data[BUFSIZ];
  	u_char *cp1, *cp2, *temp_ptr, *eom, *rr_type_ptr;
! 	u_char *cdata;
  	char *origin, *proto, dname[MAXDNAME];
  	char *ignore = "";
  	const char *badsoa_msg;
--- 1225,1231 ----
  	int i, j, tab, result, class, type, dlen, n1, n;
  	char data[BUFSIZ];
  	u_char *cp1, *cp2, *temp_ptr, *eom, *rr_type_ptr;
! 	u_char *cdata, *rdatap;
  	char *origin, *proto, dname[MAXDNAME];
  	char *ignore = "";
  	const char *badsoa_msg;
***************
*** 1218,1227 ****
--- 1239,1251 ----
  	}
  	cp += n;
  	rr_type_ptr = cp;
+ 	BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
  	GETSHORT(type, cp);
  	GETSHORT(class, cp);
  	GETLONG(ttl, cp);
  	GETSHORT(dlen, cp);
+ 	BOUNDS_CHECK(cp, dlen);
+ 	rdatap = cp;
  
  	origin = strchr(dname, '.');
  	if (origin == NULL)
***************
*** 1296,1305 ****
  		cp += n;
  		cp1 += strlen((char *) cp1) + 1;
  		if (type == T_SOA) {
! 			if ((eom - cp) < (5 * INT32SZ)) {
! 				hp->rcode = FORMERR;
! 				return (-1);
! 			}
  			temp_ptr = cp + 4 * INT32SZ;
  			GETLONG(minimum_ttl, temp_ptr);
  			n = 5 * INT32SZ;
--- 1320,1326 ----
  		cp += n;
  		cp1 += strlen((char *) cp1) + 1;
  		if (type == T_SOA) {
! 			BOUNDS_CHECK(cp, 5 * INT32SZ);
  			temp_ptr = cp + 4 * INT32SZ;
  			GETLONG(minimum_ttl, temp_ptr);
  			n = 5 * INT32SZ;
***************
*** 1313,1336 ****
  
  	case T_NAPTR:
  		/* Grab weight and port. */
  		bcopy(cp, data, INT16SZ*2);
  		cp1 = (u_char *) (data + INT16SZ*2);
  		cp += INT16SZ*2;
   
  		/* Flags */
  		n = *cp++;
  		*cp1++ = n;
  		bcopy(cp, cp1, n);
  		cp += n; cp1 += n;
   
  		/* Service */
! 		n = *cp++;
  		*cp1++ = n;
  		bcopy(cp, cp1, n);
  		cp += n; cp1 += n;
   
  		/* Regexp */
! 		n = *cp++;
  		*cp1++ = n;
  		bcopy(cp, cp1, n);
  		cp += n; cp1 += n;
--- 1334,1364 ----
  
  	case T_NAPTR:
  		/* Grab weight and port. */
+ 		BOUNDS_CHECK(cp, INT16SZ*2);
  		bcopy(cp, data, INT16SZ*2);
  		cp1 = (u_char *) (data + INT16SZ*2);
  		cp += INT16SZ*2;
   
  		/* Flags */
+ 		BOUNDS_CHECK(cp, 1);
  		n = *cp++;
+ 		BOUNDS_CHECK(cp, n);
  		*cp1++ = n;
  		bcopy(cp, cp1, n);
  		cp += n; cp1 += n;
   
  		/* Service */
! 		BOUNDS_CHECK(cp, 1);
!  		n = *cp++;
! 		BOUNDS_CHECK(cp, n);
  		*cp1++ = n;
  		bcopy(cp, cp1, n);
  		cp += n; cp1 += n;
   
  		/* Regexp */
! 		BOUNDS_CHECK(cp, 1);
!  		n = *cp++;
! 		BOUNDS_CHECK(cp, n);
  		*cp1++ = n;
  		bcopy(cp, cp1, n);
  		cp += n; cp1 += n;
***************
*** 1354,1364 ****
--- 1382,1394 ----
  	case T_RT:
  	case T_SRV:
  		/* grab preference */
+ 		BOUNDS_CHECK(cp, INT16SZ);
  		bcopy((char *)cp, data, INT16SZ);
  		cp1 = (u_char *)data + INT16SZ;
  		cp += INT16SZ;
  
  		if (type == T_SRV) {
+ 			BOUNDS_CHECK(cp, INT16SZ);
  			bcopy((char *)cp, cp1, INT16SZ*2);
  			cp1 += INT16SZ*2;
  			cp += INT16SZ*2;
***************
*** 1380,1385 ****
--- 1410,1416 ----
  
  	case T_PX:
  		/* grab preference */
+ 		BOUNDS_CHECK(cp, INT16SZ);
  		bcopy((char *)cp, data, INT16SZ);
  		cp1 = (u_char *)data + INT16SZ;
  		cp += INT16SZ;
***************
*** 1410,1415 ****
--- 1441,1447 ----
  
  		/* first just copy over the type_covered, algorithm, */
  		/* labels, orig ttl, two timestamps, and the footprint */
+ 		BOUNDS_CHECK(cp, 18);
  		bcopy( cp, cp1, 18 );
  		cp  += 18;
  		cp1 += 18;
***************
*** 1425,1432 ****
  		/* finally, we copy over the variable-length signature.
  		   Its size is the total data length, minus what we copied. */
  		n = dlen - (18 + n);
! 		if (n > (sizeof data) - (cp1 - (u_char *)data))
  			return (-1);  /* out of room! */
  		bcopy(cp, cp1, n);
  		cp += n;
  		cp1 += n;
--- 1457,1466 ----
  		/* finally, we copy over the variable-length signature.
  		   Its size is the total data length, minus what we copied. */
  		n = dlen - (18 + n);
! 		if (n > (int)((sizeof data) - (int)(cp1 - (u_char *)data))) {
! 			hp->rcode = FORMERR;
  			return (-1);  /* out of room! */
+ 		}
  		bcopy(cp, cp1, n);
  		cp += n;
  		cp1 += n;
***************
*** 1450,1455 ****
--- 1484,1497 ----
  		hp->rcode = FORMERR;
  		return (-1);
  	}
+ 	if (cp != rdatap + dlen) {
+ 		dprintf(1, (ddt,
+ 		    "encoded rdata length is %u, but actual length was %u\n",
+ 			dlen, (u_int)(cp - rdatap)));
+ 		hp->rcode = FORMERR;
+ 		return (-1);
+ 	}
+ 
  	cdata = cp1;
  	result = cp - rrp;