Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/netbsd-1-6]: src/dist/bind/bin/named Pull up revision 1.5 (requested by ...



details:   https://anonhg.NetBSD.org/src/rev/40728d4f6b12
branches:  netbsd-1-6
changeset: 528149:40728d4f6b12
user:      lukem <lukem%NetBSD.org@localhost>
date:      Fri Jun 28 11:34:35 2002 +0000

description:
Pull up revision 1.5 (requested by itojun in ticket #387):
Update to BIND 8.3.3.  Fixes buffer overrun in resolver code.

diffstat:

 dist/bind/bin/named/ns_req.c |  568 +++++++++++++++++++++++++++++++++---------
 1 files changed, 446 insertions(+), 122 deletions(-)

diffs (truncated from 970 to 300 lines):

diff -r 94f7c6053502 -r 40728d4f6b12 dist/bind/bin/named/ns_req.c
--- a/dist/bind/bin/named/ns_req.c      Fri Jun 28 11:34:16 2002 +0000
+++ b/dist/bind/bin/named/ns_req.c      Fri Jun 28 11:34:35 2002 +0000
@@ -1,8 +1,8 @@
-/*     $NetBSD: ns_req.c,v 1.4 2001/05/17 22:59:40 itojun Exp $        */
+/*     $NetBSD: ns_req.c,v 1.4.2.1 2002/06/28 11:34:35 lukem Exp $     */
 
 #if !defined(lint) && !defined(SABER)
 static const char sccsid[] = "@(#)ns_req.c     4.47 (Berkeley) 7/1/91";
-static const char rcsid[] = "Id: ns_req.c,v 8.138.2.1 2001/04/27 07:44:05 marka Exp";
+static const char rcsid[] = "Id: ns_req.c,v 8.169 2002/05/12 23:41:52 marka Exp";
 #endif /* not lint */
 
 /*
@@ -155,11 +155,11 @@
                                  int *buflenp, int *msglenp,
                                  u_char *msg, int dfd, int *ra,
                                  struct sockaddr_in from,
-                                 struct tsig_record *in_tsig);
+                                 struct tsig_record *in_tsig,
+                                 u_int16_t udpsize);
 
 static enum req_action req_iquery(HEADER *hp, u_char **cpp, u_char *eom,
-                                  int *buflenp, u_char *msg,
-                                  struct sockaddr_in from);
+                                  int *buflenp, struct sockaddr_in from);
 
 #ifdef BIND_NOTIFY
 static enum req_action req_notify(HEADER *hp, u_char **cpp, u_char *eom,
@@ -167,6 +167,118 @@
 #endif
 
 /*
+ * See if there is a OPT record at the end of the message.
+ *
+ * Results:
+ * -1  FORMERR
+ *  0  last RR is not a OPT record
+ * n>0 lenght of OPT record
+ */
+int
+ns_get_opt(u_char *msg, u_char *eom,
+          u_int8_t *versionp, u_int16_t *rcodep, u_int16_t *flagp,
+          u_int16_t *bufsizep, u_char **optionsp, size_t *optsizep)
+{
+       HEADER *hp = (HEADER *) msg;
+       u_char *start, *options, *cp;
+       u_int8_t version;
+       u_int16_t rdlen, type, bufsize, flags, optsize, rcode;
+       int i, n, root;
+
+       if (msg == NULL || eom == NULL || (msg + HFIXEDSZ) > eom)
+               return (-1);
+
+       if (ntohs(hp->arcount) == 0)
+               return (0);
+
+       cp = msg + HFIXEDSZ;
+       n = ns_skiprr(cp, eom, ns_s_qd, ntohs(hp->qdcount));
+       if (n < 0)
+               return (-1);
+       cp += n;
+       n = ns_skiprr(cp, eom, ns_s_an, ntohs(hp->ancount));
+       if (n < 0)
+               return (-1);
+       cp += n;
+       n = ns_skiprr(cp, eom, ns_s_ns, ntohs(hp->nscount));
+       if (n < 0)
+               return (-1);
+       cp += n;
+       i = ntohs(hp->arcount);
+       while (i-- > 0) {
+               start = cp;
+               if (cp >= eom)
+                       return (-1);
+               root = (*cp == 0);
+               n = dn_skipname(cp, eom);
+               if (n < 0)
+                       return (-1);
+               cp += n;
+               if (cp + (2 + 2 + 4 + 2) > eom)
+                       return (-1);
+               GETSHORT(type, cp);
+               if (type != ns_t_opt) {
+                       cp += INT16SZ + INT32SZ;        /* class, ttl */
+                       GETSHORT(rdlen, cp);
+                       if (cp + rdlen > eom)
+                               return (-1);
+                       cp += rdlen;
+                       continue;
+               }
+               /* We have the OPT record.  Check it out in detail. */
+               if (!root)
+                       return (-1);
+               GETSHORT(bufsize, cp);
+               rcode = (*cp++ <<4) + hp->rcode ;
+               version = *cp++;
+               GETSHORT(flags, cp);
+               GETSHORT(rdlen, cp);
+               if (cp + rdlen > eom)
+                       return (-1);
+               options = cp;
+               optsize = rdlen;
+               if (versionp != NULL)
+                       *versionp = version;
+               if (rcodep != NULL)
+                       *rcodep = rcode;
+               if (flagp != NULL)
+                       *flagp = flags;
+               if (bufsizep != NULL)
+                       *bufsizep = bufsize;
+               if (optionsp != NULL)
+                       *optionsp = options;
+               if (optsizep != NULL)
+                       *optsizep = optsize;
+               return (cp - start);
+       }
+       /* OPT not found */
+       return (0);
+}
+
+int
+ns_add_opt(u_char *msg, u_char *cp, size_t buflen, u_int8_t version,
+          u_int16_t rcode, u_int16_t size, u_int16_t flags,
+          u_char *options, size_t optlen)
+{
+       HEADER *hp = (HEADER *) msg;
+
+       if ((cp + 1 + 2 + 2 + 4 + 2 + optlen) > (msg + buflen))
+               return (-1);
+
+       *cp++ = 0;                      /* "." */
+       PUTSHORT(ns_t_opt, cp);         /* type */
+       PUTSHORT(size, cp);             /* class (udp size) */
+       *cp++ = (rcode >> 4) & 0xff;    /* ttl (rcode + version + flags) */
+       hp->rcode = rcode & 0xf;
+       *cp++ = version;
+       PUTSHORT(flags, cp);
+       PUTSHORT(optlen, cp);           /* rdlen */
+       memcpy(cp, options, optlen);    /* options */
+       hp->arcount = htons(ntohs(hp->arcount) + 1);
+       return (1 + 2 + 2 + 4 + 2 + optlen);
+}
+
+/*
  * Process request using database; assemble and send response.
  */
 void
@@ -175,8 +287,8 @@
 {
        HEADER *hp = (HEADER *) msg;
        u_char *cp, *eom;
-       enum req_action action;
-       int n, ra, has_tsig, tsig_size, sig2len;
+       enum req_action action = Return;
+       int n, ra, has_tsig, tsig_size = 0, opt_size = 0, sig2len;
        u_char *tsigstart;
        u_char sig[TSIG_SIG_SIZE], sig2[TSIG_SIG_SIZE];
        struct tsig_record *in_tsig = NULL;
@@ -184,8 +296,14 @@
        int msglen_orig = msglen;
        int buflen_orig = buflen;
        int siglen = sizeof sig;
-       DST_KEY *key;
+       DST_KEY *key = NULL;
        time_t tsig_time;
+       int opt = 0;
+       u_int8_t version = 0;
+       u_int16_t rcode = ns_r_noerror;
+       u_int16_t udpsize = 0;
+       int drop;
+       int tsig_adjust = 0;
 
 #ifdef DEBUG
        if (debug > 3) {
@@ -194,18 +312,30 @@
        }
 #endif
        
+       drop = drop_port(ntohs(from.sin_port));
+       if (qsp == NULL && drop == 1)
+               return;
+
        tsigstart = ns_find_tsig(msg, msg + msglen);
        if (tsigstart == NULL)
                has_tsig = 0;
        else {
                char buf[MAXDNAME];
+               u_char tmp[NS_MAXCDNAME];
 
                has_tsig = 1;
-               n = dn_expand(msg, msg + msglen, tsigstart, buf, sizeof buf);
+               n = ns_name_unpack(msg, msg + msglen, tsigstart,
+                                  tmp, sizeof tmp);
+               if (n > 0) {
+                       tsig_adjust = dn_skipname(tmp, tmp + sizeof(tmp)) - n;
+                       if (ns_name_ntop(tmp, buf, sizeof buf) == -1)
+                               n = -1;
+                       else if (buf[0] == '.')
+                               buf[0] = '\0';
+               }
                if (n < 0) {
                        ns_debug(ns_log_default, 1,
-                                "ns_req: bad TSIG key name",
-                                buf);
+                                "ns_req: bad TSIG key name");
                        error = ns_r_formerr;
                        hp->rcode = ns_r_formerr;
                        key = NULL;
@@ -263,6 +393,8 @@
                in_tsig->siglen = siglen;
                memcpy(in_tsig->sig, sig, siglen);
                tsig_size = msglen_orig - msglen;
+               /* AXFR/IXFR need the uncompressed tsig size. */
+               in_tsig->tsig_size = tsig_size + tsig_adjust;
        } else if (has_tsig) {
                action = Finish;
                in_tsig = memget(sizeof(struct tsig_record));
@@ -271,6 +403,7 @@
                in_tsig->key = NULL;
                in_tsig->siglen = 0;
                tsig_size = msg + msglen - tsigstart;
+               in_tsig->tsig_size = tsig_size;
                msglen = tsigstart - msg;
        }
 
@@ -278,6 +411,30 @@
        nsid_hash((u_char *)&tt, sizeof(tt));
        nsid_hash(msg, (msglen > 512) ? 512 : msglen);
 
+       if (error == NOERROR) {
+
+               opt = ns_get_opt(msg, msg + msglen, &version,
+                                NULL, NULL, &udpsize, NULL, NULL);
+               if (opt < 0) {
+                       rcode = ns_r_formerr;
+                       action = Finish;
+               } else if (opt == 0) {
+                       if (qsp == NULL && buflen > PACKETSZ)
+                               buflen_orig = buflen = PACKETSZ;
+               } else if (opt > 0) {
+                       if (version != 0) {
+                               rcode = ns_r_badvers;
+                               action = Finish;
+                       }
+                       opt_size = 11;
+                       if (udpsize < 512)
+                               udpsize = 512;
+                       if (qsp == NULL && buflen > udpsize)
+                               buflen_orig = buflen = udpsize;
+               }
+       } else if (qsp == NULL && buflen > PACKETSZ)
+               buflen_orig = buflen = PACKETSZ;
+
        /*
         * It's not a response so these bits have no business
         * being set. will later simplify work if we can
@@ -293,6 +450,8 @@
 
        if (error == NOERROR)
                hp->rcode = ns_r_noerror;
+       if (rcode == ns_r_noerror)
+               rcode = hp->rcode;
        cp = msg + HFIXEDSZ;
        eom = msg + msglen;
        buflen -= HFIXEDSZ;
@@ -300,16 +459,17 @@
        free_addinfo(); /* sets addcount to zero */
        dnptrs[0] = NULL;
 
-       if (error == NOERROR) {
+       if (error == NOERROR && rcode == ns_r_noerror) {
                switch (hp->opcode) {
                case ns_o_query:
                        action = req_query(hp, &cp, eom, qsp,
                                           &buflen, &msglen,
-                                          msg, dfd, &ra, from, in_tsig);
+                                          msg, dfd, &ra, from,
+                                          in_tsig, udpsize);
                        break;
 
                case ns_o_iquery:
-                       action = req_iquery(hp, &cp, eom, &buflen, msg, from);
+                       action = req_iquery(hp, &cp, eom, &buflen, from);
                        break;
 
 #ifdef BIND_NOTIFY
@@ -320,8 +480,7 @@
 
 #ifdef BIND_UPDATE
                case ns_o_update:
-                       action = req_update(hp, cp, eom, msg, qsp, dfd, from,
-                                           in_tsig);
+                       action = req_update(hp, cp, eom, msg, from, in_tsig);
                        break;
 #endif /* BIND_UPDATE */
 
@@ -337,6 +496,7 @@
                        hp->rcode = ns_r_notimpl;
                        action = Finish;



Home | Main Index | Thread Index | Old Index