summaryrefslogtreecommitdiffstats
path: root/contrib/bind/named/ns_resp.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bind/named/ns_resp.c')
-rw-r--r--contrib/bind/named/ns_resp.c156
1 files changed, 115 insertions, 41 deletions
diff --git a/contrib/bind/named/ns_resp.c b/contrib/bind/named/ns_resp.c
index d0f3221..d48da23 100644
--- a/contrib/bind/named/ns_resp.c
+++ b/contrib/bind/named/ns_resp.c
@@ -1,6 +1,6 @@
#if !defined(lint) && !defined(SABER)
static char sccsid[] = "@(#)ns_resp.c 4.65 (Berkeley) 3/3/91";
-static char rcsid[] = "$Id: ns_resp.c,v 8.38 1997/06/01 20:34:34 vixie Exp vixie $";
+static char rcsid[] = "$Id: ns_resp.c,v 8.41 1998/04/07 04:59:45 vixie Exp $";
#endif /* not lint */
/*
@@ -132,7 +132,8 @@ struct flush_set {
static void rrsetadd __P((struct flush_set *, char *,
struct databuf *)),
rrsetupdate __P((struct flush_set *, int flags)),
- flushrrset __P((struct flush_set *));
+ 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)),
@@ -239,7 +240,7 @@ ns_resp(msg, msglen)
register struct databuf *ns, *ns2;
register u_char *cp;
u_char *eom = msg + msglen;
- struct flush_set *flushset;
+ struct flush_set *flushset = NULL;
struct sockaddr_in *nsa;
struct databuf *nsp[NSMAX];
int i, c, n, qdcount, ancount, aucount, nscount, arcount, arfirst;
@@ -264,8 +265,6 @@ ns_resp(msg, msglen)
struct fwdinfo *fwd;
char *tname = NULL;
- free_related_additional();
-
nameserIncr(from_addr.sin_addr, nssRcvdR);
nsp[0] = NULL;
hp = (HEADER *) msg;
@@ -302,6 +301,10 @@ ns_resp(msg, msglen)
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,
@@ -581,16 +584,12 @@ ns_resp(msg, msglen)
goto formerr;
}
tp += n;
- GETSHORT(type, tp);
- if (tp >= eom) {
+ if (tp + 2 * INT16SZ > eom) {
formerrmsg = outofDataAuth;
goto formerr;
}
+ GETSHORT(type, tp);
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)) {
@@ -645,6 +644,7 @@ ns_resp(msg, msglen)
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) {
@@ -652,14 +652,15 @@ ns_resp(msg, msglen)
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 */
- if (tp >= eom) {
- formerrmsg = outofDataAnswer;
- goto formerr;
- }
+ rdatap = tp; /* start of rdata */
if (!ns_nameok(name, class, response_trans,
ns_ownercontext(type, response_trans),
name, from_addr.sin_addr)) {
@@ -675,10 +676,6 @@ ns_resp(msg, msglen)
formerrmsg = msgbuf;
goto formerr;
}
- if ((u_int)dlen < (5 * INT32SZ)) {
- formerrmsg = dlenUnderrunAnswer;
- goto formerr;
- }
if (0 >= (n = dn_skipname(tp, eom))) {
formerrmsg = skipnameFailedAnswer;
@@ -690,7 +687,16 @@ ns_resp(msg, msglen)
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);
@@ -786,12 +792,18 @@ ns_resp(msg, msglen)
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;
}
@@ -921,13 +933,11 @@ ns_resp(msg, msglen)
}
rrsetadd(flushset, name, dp);
}
+ free_related_additional();
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);
+ free_flushset(flushset);
}
if (lastwascname && !externalcname)
syslog(LOG_DEBUG, "%s (%s)", danglingCname, aname);
@@ -1365,6 +1375,14 @@ ns_resp(msg, msglen)
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;
@@ -1375,7 +1393,7 @@ rrextract(msg, msglen, rrp, dpp, dname, namelen, tnamep)
int namelen;
char **tnamep;
{
- register u_char *cp;
+ register u_char *cp, *eom, *rdatap;
register int n;
int class, type, dlen, n1;
u_int32_t ttl;
@@ -1389,15 +1407,19 @@ rrextract(msg, msglen, rrp, dpp, dname, namelen, tnamep)
*dpp = NULL;
cp = rrp;
- if ((n = dn_expand(msg, msg + msglen, cp, dname, namelen)) < 0) {
+ 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)) {
@@ -1456,8 +1478,7 @@ rrextract(msg, msglen, rrp, dpp, dname, namelen, tnamep)
case T_MR:
case T_NS:
case T_PTR:
- n = dn_expand(msg, msg + msglen, cp,
- (char *)data, sizeof data);
+ n = dn_expand(msg, eom, cp, (char *)data, sizeof data);
if (n < 0) {
hp->rcode = FORMERR;
return (-1);
@@ -1483,8 +1504,7 @@ rrextract(msg, msglen, rrp, dpp, dname, namelen, tnamep)
context = mailname_ctx;
/* FALLTHROUGH */
soa_rp_minfo:
- n = dn_expand(msg, msg + msglen, cp,
- (char *)data, sizeof data);
+ n = dn_expand(msg, eom, cp, (char *)data, sizeof data);
if (n < 0) {
hp->rcode = FORMERR;
return (-1);
@@ -1495,11 +1515,15 @@ rrextract(msg, msglen, rrp, dpp, dname, namelen, tnamep)
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, msg + msglen, cp, (char *)cp1, n1);
+ n = dn_expand(msg, eom, cp, (char *)cp1, n1);
if (n < 0) {
hp->rcode = FORMERR;
return (-1);
@@ -1516,7 +1540,9 @@ rrextract(msg, msglen, rrp, dpp, dname, namelen, tnamep)
cp += n;
cp1 += strlen((char *)cp1) + 1;
if (type == T_SOA) {
- bcopy(cp, cp1, n = 5 * INT32SZ);
+ n = 5 * INT32SZ;
+ BOUNDS_CHECK(cp, n);
+ bcopy(cp, cp1, n);
cp += n;
cp1 += n;
}
@@ -1526,30 +1552,37 @@ rrextract(msg, msglen, rrp, dpp, dname, namelen, tnamep)
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, msg + msglen, cp, (char *)cp1,
+ n = dn_expand(msg, eom, cp, (char *)cp1,
sizeof data - (cp1 - data));
if (n < 0) {
hp->rcode = FORMERR;
@@ -1574,19 +1607,21 @@ rrextract(msg, msglen, rrp, dpp, dname, namelen, tnamep)
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, msg + msglen, cp, (char *)cp1,
+ n = dn_expand(msg, eom, cp, (char *)cp1,
sizeof data - (cp1 - data));
if (n < 0) {
hp->rcode = FORMERR;
@@ -1611,13 +1646,14 @@ rrextract(msg, msglen, rrp, dpp, dname, namelen, tnamep)
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, msg + msglen, cp, (char *)cp1,
- sizeof data - INT16SZ);
+ n = dn_expand(msg, eom, cp, (char *)cp1,
+ sizeof data - INT16SZ);
if (n < 0) {
hp->rcode = FORMERR;
return (-1);
@@ -1628,9 +1664,13 @@ rrextract(msg, msglen, rrp, dpp, dname, namelen, tnamep)
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, msg + msglen, cp, (char *)cp1, n1);
+ n = dn_expand(msg, eom, cp, (char *)cp1, n1);
if (n < 0) {
hp->rcode = FORMERR;
return (-1);
@@ -1653,6 +1693,7 @@ rrextract(msg, msglen, rrp, dpp, dname, namelen, tnamep)
/* 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);
@@ -1697,23 +1738,31 @@ rrextract(msg, msglen, rrp, dpp, dname, namelen, tnamep)
/* 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, msg + msglen, cp,
- (char *)cp1, (sizeof data) - 18);
- if (n < 0)
+ 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 > (sizeof data) - (cp1 - (u_char *)data))
+ 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;
@@ -1728,6 +1777,18 @@ rrextract(msg, msglen, rrp, dpp, dname, namelen, tnamep)
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",
@@ -3063,6 +3124,17 @@ flushrrset(fs)
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
@@ -3125,8 +3197,10 @@ add_related_additional(name)
if (num_related >= MAX_RELATED - 1)
return;
for (i = 0; i < num_related; i++)
- if (strcasecmp(name, related[i]) == 0)
+ if (strcasecmp(name, related[i]) == 0) {
+ free(name);
return;
+ }
related[num_related++] = name;
}
OpenPOWER on IntegriCloud