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 --- 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 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 . ! 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 .) 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 . ! The official mailing lists are: - users/admins ! (use *-request@* for admin mail) - developers ! The official Usenet newsgroups are: ! ! ! BIND is maintained by: The Internet Software Consortium ! (see ) ! ! Bug reports should be sent to: 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 --- 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 *************** *** 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;